using System;
using System.Windows.Forms;

//====================================================================
// Represents the facade for the whole Chat functionality.
// Singleton.
// HiddenCarrier knows about and uses this class.
//====================================================================
public class Chat : IDisposable
{
	static Chat()
	{
		mInstance = new Chat();
	}

	public Chat()
	{
		mUsers = new UserList();
		Users.UserConnected += OnUserConnected;
		Users.UserDisconnected += OnUserDisconnected;
		Users.UserReceivedText += OnUserReceivedText;
		Users.UserStatusChanged += OnUserStatusChanged;
		Users.Load();
	}

	public event UserConnectedEventHandler UserConnected;
	public delegate void UserConnectedEventHandler(RemoteUser Sender);
	public event UserDisconnectedEventHandler UserDisconnected;
	public delegate void UserDisconnectedEventHandler(RemoteUser Sender);
	public event UserReceivedTextEventHandler UserReceivedText;
	public delegate void UserReceivedTextEventHandler(RemoteUser Sender, string Text);
	public event UserStatusChangedEventHandler UserStatusChanged;
	public delegate void UserStatusChangedEventHandler(RemoteUser Sender);

	//====================================================================
	// 1. Server-functionality layer. Port listener.
	//====================================================================

	// Port listener that exists throughout the execution of the program.
	// Created and started in Chat.Start()
	private LocalPort mListener;
	public LocalPort Listener
	{
		get
		{
			return mListener;
		}
		set
		{
			if (mListener != null)
			{
				mListener.EstablishedConnection -= Listener_EstablishedConnection;
			}
			mListener = value;
			if (mListener != null)
			{
				mListener.EstablishedConnection += Listener_EstablishedConnection;
			}
		}
	}

	//====================================================================
	// 2. Client-functionality layer. User list.
	//====================================================================

	// This user's contact list.
	private UserList mUsers;
	public UserList Users
	{
		get
		{
			return mUsers;
		}
	}

	//====================================================================
	// Initializing
	//====================================================================

	private static readonly Chat mInstance;

	// Thread-safe Singleton instance
	public static Chat Instance
	{
		get
		{
			return mInstance;
		}
	}

	public void Start()
	{
		Listener = new LocalPort();
		Users.Connect();
	}

	//====================================================================
	// Terminating
	//====================================================================

	~Chat()
	{
		Dispose();
	}

	public void Dispose()
	{
		if ((Listener != null))
		{
			Users.Disconnect();
			Listener.Dispose();
			Listener = null;
		}
	}

	//====================================================================
	// Established incoming connection.
	// Called from Listener object (Class LocalPort).
	//====================================================================

	private void Listener_EstablishedConnection(string Name, string UserAddress, UserConnection ExistingConnection)
	{
		RemoteUser NewlyConnectedUser = Users[Name];

		if ((NewlyConnectedUser != null))
		{
			NewlyConnectedUser.ConnectRespond(ExistingConnection);
		}
		else
		{
			if (MessageBox.Show("Would you like to add a new user " + Name + " to your contact list?", "New user requests connection", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
			{
				Users.AddUserIncomingRequest(Name, UserAddress, ExistingConnection);
			}
		}
	}

	//====================================================================
	// Pass on the events further along the chain of responsibility.
	//====================================================================

	#region " User list events "

	private void OnUserConnected(RemoteUser Sender)
	{
		if (UserConnected != null)
		{
			UserConnected(Sender);
		}
	}

	private void OnUserDisconnected(RemoteUser Sender)
	{
		if (UserDisconnected != null)
		{
			UserDisconnected(Sender);
		}
	}

	private void OnUserReceivedText(RemoteUser Sender, string Text)
	{
		if (UserReceivedText != null)
		{
			UserReceivedText(Sender, Text);
		}
	}

	private void OnUserStatusChanged(RemoteUser Sender)
	{
		if (UserStatusChanged != null)
		{
			UserStatusChanged(Sender);
		}
	}

	#endregion

}
